#!/usr/bin/env python
# -*- coding: GBK -*-

import os, sys, time, string
import thread, shutil, glob, fnmatch
import commands, stat, math
import ConfigParser
from xml.dom.minidom import parse
__version__ = "1.10.02"

def _keyPath(filePath):
    #print filePath.upper
    return (os.stat(filePath).st_mtime, filePath.lower)
    
class commRunTest:
    def __init__(self):
        pass
    
    ## Check the running status of the processes.
    #@param self The object pointer.
    #@param name Process name.
    #@param ParamList 必须出现的参数。缺省值为空。
    #@return Correct thread number,Error thread number
    def CheckProcess(self,name,ParamList=[]):
        while True:
            nCorrect1,nError1 = self.CheckProcessOnce(name,ParamList)
            time.sleep(0.01)
            nCorrect2,nError2 = self.CheckProcessOnce(name,ParamList)
        
            #double check
            if(nCorrect1 != nCorrect2 or nError1 != nError2):
                continue
            else:
                break
        return nCorrect1,nError1
    
    ## 该函数负责在不同的操作系统版本上调用ps命令取得命令行，然后将命令行按照空格分割成一个list。
    #  该函数也负责处理各种通过解释器执行的程序的命令行。
    #@param self The object pointer.
    #@return 返回一个Tuple: 列数,包含了程序名的命令列表文本。
    # 返回列数的原因是由于ps的参数不同导致的需要分析的列数的不同。
    def GetCmdLines(self):
        ##各种解释执行的程序使用的解释器
        
        #Call system command ps to get process named 'name'.See below example
        #[ywang@45 src]$ ps -eL --cols 10240|grep Result
        #    31137 31137 pts/5    00:00:00 Result
        #    31137 31138 pts/5    00:00:00 Result
        #    31137 31139 pts/5    00:00:00 Result    
        #cmd = 'ps -eL --cols 10240|grep  ' + name        
        #使用上面的命令在进程名称超过15个字符时会被截断
        
        
        #UID        PID  PPID  C STIME TTY          TIME CMD
        #root         1     0  0 08:52 ?        00:00:00 init [3]
        #root         2     1  0 08:52 ?        00:00:00 [migration/0]
        #root         3     1  0 08:52 ?        00:00:00 [ksoftirqd/0]
        #root         4     1  0 08:52 ?        00:00:00 [migration/1]
        #root         5     1  0 08:52 ?        00:00:00 [ksoftirqd/1]
        cmd = 'ps -efL --cols 10240'
        #使用上面的命令时，在有-f参数时，在进程名称超过15个字符时不会被截断
        ret = commands.getoutput(cmd)
        #print ret
        #在老版本的linux上面没有ps -efL命令，此时会报错，使用ps auxm代替。
        if(ret.find('ps: error: Use -m to print threads') == -1):
            return 9,ret;
        else:
            cmd = 'ps auxm --cols 10240'
            ret = commands.getoutput(cmd)
            return 10,ret;
        return 0,""
        
    
    ## Check the running status of the processes.
    #@param self The object pointer.
    #@param name Process name.
    #@param ParamList 必须出现的参数。缺省值为空。
    #@param CmdLines 命令行文本参数，当该参数为空时，本函数调用self.GetCmdLines获取命令行参数。
    #@return Correct thread number,Error thread number
    def CheckProcessOnce(self,name,ParamList=[],CmdLines=""):
        """Check the running status of the processes."""
        ColIndex = 9
        if len(CmdLines) == 0:
            ColIndex,CmdLines = self.GetCmdLines()

        ret = CmdLines.split('\n')
        #print ret
        nDefunctCount = 0
        nCorrectCount = 0
        for line in ret:
            cols = line.split()
            if(line.find(name) == -1):
                continue
            if(len(cols) < ColIndex + 1):
                return nCorrectCount,nDefunctCount

    
            bAllMatch = True
            ##检查name是否出现在命令行中
            bFind = False
            for item in cols[ColIndex:]:            
                cmdStr = item.strip(' ./')
                if(name == cmdStr):
                    #print cmdStr
                    bFind = True
            if not bFind:
                bAllMatch = False
            else:
                ##检查所有参数是否出现在命令行中
                for one in ParamList:
                    #print one
                    bFind = False
                    for item in cols[ColIndex:]:            
                        #cmdStr = item.strip(' ./')
                        if(one == cmdStr):
                            #print cmdStr
                            bFind = True
                            continue
                    if not bFind:
                        bAllMatch = False

            if bAllMatch:
                nCorrectCount = nCorrectCount + 1
                #print nCorrectCount
                if(line.find('defunct') != -1):
                    nDefunctCount = nDefunctCount + 1
        
        #print 'nCorrectCount = %d' % (nCorrectCount)                
        return nCorrectCount,nDefunctCount
    
    ## Run a process at back groud.
    #@param self Object itself
    #@param path Command path
    #@param cmd Command line.
    #@return Boolean value,PID will be returned.
    #True on success,otherwise False will be returned.
            
    ## Check whether process with name is running.
    #   This function do not check the thread number.
    #@param self The object pointer.
    #@param name Process name.
    #@return True means is running.
    def IsRunningOfPragram(self,name):
        """ Check whether this process is running."""
        nCorrect,nError = self.CheckProcess(name)
        #print "sfsdfsdf %(Correct)d %(Error)d" % {'Correct':nCorrect,'Error':nError}
        if((nCorrect > 0) and (nError == 0)):
            return True
        return False
    
    def IsProgramInGuard(self, programName):
        '''checking the programe is running whether or not in the guard
        return the bool of true or false'''
        if not programName:
            raise Exception("empty programe!")
    
        filePath = "/dev/shm/process_list.xml"
        try:
            file = open(filePath)
        except IOError:
            raise Exception("open the file %s fail" % filePath) 
    
        document = parse(file)
        nodelist = document.getElementsByTagName("Process")
        for processNode in nodelist:
            if processNode.hasAttribute("Name"):
                #print processNode.getAttribute("Name")
                if programName.lower() == processNode.getAttribute("Name").lower():
                    enableNode = processNode.getElementsByTagName("Enable")[0]
                    #print enableNode.nodeName
                    tmpEnableNodeText = enableNode.childNodes [0].nodeValue
                    #print tmpEnableNodeText
                    if not tmpEnableNodeText:
                        continue
        
                    StatusNode = ""
                    if "YES" == tmpEnableNodeText.upper():
                        StatusNode = processNode.getElementsByTagName("Status")[0]
                    if not StatusNode:
                        continue
                    tmpStatusNodeText = StatusNode.childNodes[0].nodeValue
                    #print tmpStatusNodeText
                    if not tmpStatusNodeText:
                        continue
            
                    if "START" == tmpStatusNodeText.upper():
                        return True
                    
        return False
    
    def IsProgramInFudeGuard(self, PRunProgameCmd,PworkPath):
        '''checking the programe is running whether or not in the guard
        return the bool of true or false'''
    
        fileDir = "/opt/FUDE-0.4/fude/etc/guard/conf.d/"
        
        if not os.path.exists(fileDir):
            return False
        
        #print PRunProgameCmd
        #print PworkPath
        files = os.listdir(fileDir)
        for FileName in files:
            try:
                #print FileName
                if not fnmatch.fnmatch(FileName, "*xml"):
                    continue
                
                xmlFile = open(os.path.join(fileDir,FileName))
                document = parse(xmlFile)
                nodelist = document.getElementsByTagName("Process")
                for processNode in nodelist:
                    if not processNode.hasAttribute("Enable"):
                        continue
                    if not "YES" == processNode.getAttribute("Enable").upper():
                        continue
                    WorkPathNode = processNode.getElementsByTagName("WorkPath")[0]
                    WorkPath = WorkPathNode.childNodes [0].nodeValue
                    #print WorkPath.strip()
                    CmdNode = processNode.getElementsByTagName("StartCmd")[0]
                    Cmd = CmdNode.childNodes [0].nodeValue
                   #print "%s.find(%s)" %(Cmd.strip(),PRunProgameCmd)
                    #print "%s == %s" %(WorkPath.strip(),PworkPath)
                    if (Cmd.strip().find(PRunProgameCmd)> 0 and WorkPath.strip().rstrip("/") == PworkPath.rstrip("/")):
                        return True
            except Exception, msg:
                print "check the progame: %s in the fude guard Error: %s " %(PRunProgameCmd,msg)
                        
        return False
        
    def GetHDUse(self, subareaPath):
        '''check the pesentage of the hard disk's use
        return the string of the pesentage of the hard disk's use '''
        if not subareaPath:
            raise Exception("empty subareaPath!")
        if not os.path.exists(subareaPath):
            raise Exception("not exist subareaPath: " + subareaPath)
        
        st = os.statvfs(subareaPath)
        #print st.f_bfree
        #print st.f_blocks
        #print st.f_bavail 
        fHDuse = float(st.f_blocks - st.f_bfree) / float(st.f_blocks - st.f_bfree + st.f_bavail)
        tmp = str(int(math.ceil(fHDuse * 100))) + "%"
        #print "%s : %s" %(subareaPath,tmp)
        return tmp

    
    def GetInodeUse(self, subareaPath):
        """check the pesentage of the hard I_node's use
        return the string of  the pesentage of the I_node"""
        if not subareaPath:
            raise Exception("empty subareaPath!")
        if not os.path.exists(subareaPath):
            raise Exception("not exist subareaPath: " + subareaPath)
        
        st = os.statvfs(subareaPath)
        #print subareaPath
        #print "****************"
        #print st.f_files
        #print st.f_ffree
        #print st.f_favail
        #print "****************"
        fInodeUse = float(st.f_files - st.f_ffree) / float(st.f_files - st.f_ffree + st.f_favail)
        tmp = str(int(math.ceil(fInodeUse * 100))) + "%"
        return tmp
    
    def GetVersionOfPragram(self, programName):
        """check the programe's version 
        return the string of the programe's version """
        line = commands.getstatusoutput(programName + " -v")
        if line[0] > 0:
            raise Exception("check the command: " + programName + " -v")
        tmpStrVesion = line[1]
        if not tmpStrVesion:
            return tmpStrVesion
        verstionStart = tmpStrVesion.lower().find("version")
        verstionEnd = tmpStrVesion.find(os.linesep, verstionStart)
        if verstionEnd == -1:
            return  tmpStrVesion[verstionStart:] 
        return tmpStrVesion[verstionStart:verstionEnd] 
    
    def _checkSmbStr(self, smbStr):
            if smbStr.startswith("smbmount") or smbStr.startswith("mount"):
                if smbStr.find("-o") > 0:
                    if smbStr.find("username") > 0:
                        if smbStr.find("password",smbStr.find("username")) > 0:
                            return True
            return False
        
    def _getLocalDirBySmbStr(self, smbStr):
        smbStrList = smbStr.split()
        if smbStrList:
            for tmpSmbDir in smbStrList:
                if tmpSmbDir.startswith(r"/") and not tmpSmbDir.startswith(r"//"):
                    if tmpSmbDir.strip(r"/"):
                        #print tmpSmbDir
                        return tmpSmbDir

        return ""
        
    def SmbCheck(self):
        """checking all the Smbmount in the rc.local is availability in fact
        return the list of unavailablity Smbmount or return none"""
        rcFilePath = "/etc/rc.local"
        try:
            file = open(rcFilePath)
        except IOError:
            raise Exception("open the file %s fail" % rcFilePath)

        errorSmb = []        
        for line in file:
            if not line:
                #print "empty line "
                continue
            
            tmpline = line.strip()
            if tmpline:
                if self._checkSmbStr(tmpline):
                    localdir = self._getLocalDirBySmbStr(tmpline)
                    #print localdir
                    if localdir:
                        if os.path.ismount(localdir):
                            try:
                                #os.mkdir(os.path.join(localdir,"tmpp"))
                                tmpfile = open(os.path.join(localdir,"tmpp.sw"),"a")
                                tmpHDUse = self.GetHDUse(localdir)
                                #print "smb dir user: %s " %tmpHDUse
                                if (int(tmpHDUse.strip("%"))>80):
                                    errorSmb.append(localdir + " had used:" + tmpHDUse)
                                os.remove(os.path.join(localdir,"tmpp.sw"))
                                continue
                            except Exception, msg: 
                                #print msg
                                errorSmb.append(localdir + " is error smb")
                            
                        else:
                            #print "error smb dir %s" % localdir
                            errorSmb.append(localdir + " is not smb")
        file.close()
                            
        return errorSmb                              
    
    def GetTailLinesOfErrorLog(self, ErrorLogFullPath, tailLine=10):
        """ErrorLogFullPath:the error log full Path
        tailLine:will return the number of rows of the ErrorLog'tail
        return the list of the ErrorLog'tail appointed lines"""
        if not ErrorLogFullPath:
            raise Exception("empty ErrorLogFullPath!")
        if not os.path.exists(ErrorLogFullPath):
            raise Exception("not exist file: " + ErrorLogFullPath)
        
        tmpCmd = "tail -" + str(tailLine) + " " + ErrorLogFullPath
        line = commands.getstatusoutput(tmpCmd)
        if line[0] > 0:
            raise Exception("check the command: " + tmpCmd)
        tmpList = []
        if line[1]:
            tmpList = line[1].split("\n")
          
        return tmpList
    
    def GetLogLines(self, LogFullPath, grepCondition=""):
        """return the int of the number of rows of the logfile lines
        cat /home/wshi/home/IDC/log/20090804FTP.log |wc -l"""
        if not LogFullPath:
            raise Exception("empty logFullPath!")
        if not os.path.exists(LogFullPath):
            raise Exception("not exist file: " + LogFullPath)
        
        tmpCmd = ""
        if grepCondition:
            tmpCmd = "grep " + grepCondition + " " + LogFullPath + " |wc -l"
        else:
            tmpCmd = "cat LogFullPath |wc -l"
            
        line = commands.getstatusoutput(tmpCmd)
        if line[0] > 0:
            raise Exception("Error the command: " + tmpCmd)
        lineNum = 0
        try:
            lineNum = int(line[1])
        except Exception, msg:
            raise Exception("Conv the " + line[1] + " to int error: " + str(msg))
        return lineNum
    
        
    def GetFileAndRecordNum(self, awkComm):
        if not awkComm:
            raise Exception("empty comand!")
        line = commands.getstatusoutput(awkComm)
        if line[0] > 0:
            raise Exception("check the command: " + awkComm)
        
        tmpFileAndRecordNum = line[1]
        RecordNum = tmpFileAndRecordNum[:tmpFileAndRecordNum.find("(")]
        fileNum = tmpFileAndRecordNum[tmpFileAndRecordNum.find("(") + 1:tmpFileAndRecordNum.find(")")]
        return [fileNum,RecordNum]
    
    def Command(self,command):
        if not command:
            raise Exception("empty comand!")
        line = commands.getstatusoutput(command)
        if line[0] > 0:
            raise Exception("check the command: " + command)
        return line[1]
        
    def GetNewestFile(self, dirPath, condition=""):
        """fileFullPathList:file full path list
        return the new sort list of the newestfilefulList"""
        if not dirPath:
            raise Exception("empty dirction!")
        if not os.path.exists(dirPath):
            raise Exception("not exist dir: " + dirPath)
        
        fileFullPathList = self._GetFileLstByCondtiion(dirPath, condition)
        if len(fileFullPathList) < 1:
            return []
        
        fileFullPathList.sort(key=_keyPath)
        fileFullPathList.reverse()
        return fileFullPathList
    
    def _GetFileLstByCondtiion(self, dirPath, condition=""):
        rtnList = []
        filelst = os.listdir(dirPath)
        for file in filelst:
            if os.path.isfile(os.path.join(dirPath, file)):
                if condition:
                    if fnmatch.fnmatchcase(file, condition):
                        rtnList.append(os.path.join(dirPath, file))
                else:
                    rtnList.append(os.path.join(dirPath, file))
        return rtnList
        
    def IsExistFile(self, fileFullPath):
        """Test whether a path exists.  Returns False for broken symbolic links"""
        try:
            st = os.stat(fileFullPath)
        except os.error:
            return False
        return True

    def _StatFileOrDirCount(self, dirPath):
        fileList = os.listdir(dirPath)
        fileCount = 0
        dirCount = 0
        for fileOrDir in fileList:
            if os.path.isdir(os.path.join(dirPath, fileOrDir)):
                dirCount += 1
                tmpfileCount, tmpdirCount = self._StatFileOrDirCount(os.path.join(dirPath, fileOrDir))
                dirCount += tmpdirCount
                fileCount += tmpfileCount
            else:
                fileCount += 1
        return (fileCount, dirCount)
    
    def GetOverStock(self, dirPath):
        """return the two length of the tuple ,the first is the number of files,the last is the list of the file names when
        the number of files is less than five"""
        if not dirPath:
            raise Exception("empty dirPath!")
        if not os.path.exists(dirPath):
            raise Exception("not exists the directory: " + dirPath)
        fileCount = 0
        dirCount = 0
        
        fileCount, dirCount = self._StatFileOrDirCount(dirPath)
        tmpFileList = []
        if (fileCount > 0 and fileCount <= 5 and dirCount <= 2):
            #print dirPath
            #print os.listdir(dirPath)
            for file in os.listdir(dirPath):
                tmpFileList.append(file)
                
        return [str(fileCount), str(dirCount), tmpFileList]
            
    def _GetPathList(self, confPath):
        import ConfigParser
        cf = ConfigParser.ConfigParser()
        cf.read(confPath)
        
        def isInList(element, dstList):
            for tmplst in dstList:
                if element == tmplst:
                    return True
            return False
            
        rtnFileOrDirLst = []
        sectionList = cf.sections()
        #print sectionList
        for section in sectionList:
            keyAndValueList = cf.items(section)
            for tmppair in keyAndValueList:
                key, value = tmppair
                if not value:
                    continue
                
                tmpDirList = []
                if value.strip().startswith("/"):
                    #print " the file or dir path is %s " %value
                    if value.find(",") != - 1:
                        tmpDirList = value.split(",")
                    elif (value.find(";") != - 1):
                        tmpDirList = value.split(";")
                    else:
                        tmpDirList = [value]
                    for tmplst in tmpDirList:
                        tmplst = tmplst.strip()
                        if isInList(tmplst, rtnFileOrDirLst):
                            continue
                        else:
                            rtnFileOrDirLst.append(tmplst)
        
        #print "*********************"
        #print  rtnFileOrDirLst           
        return rtnFileOrDirLst

    def ExistFileOrDirInConf(self, confPath):
        if not confPath:
            raise Exception("empty confPath!")
        
        errorPathList = []
        FileOrDirLst = self._GetPathList(confPath)
        for tmplst in FileOrDirLst:
            tmplst = tmplst.strip()
            if self.IsExistFile(tmplst):
                continue
            else:
                errorPathList.append(tmplst)
        return errorPathList
    
    def GetPathFromConf(self,ConfPath,section,option):
        if not os.path.exists(ConfPath):
            raise Exception("not Exists %s" %ConfPath)
        
        cf = ConfigParser.ConfigParser()
        cf.read(ConfPath)
        return cf.get(section,option)
    
    def Exists(self,ConfPath,section,option):
        if not os.path.exists(ConfPath):
            raise Exception("not Exists %s" %ConfPath)
        
        cf = ConfigParser.ConfigParser()
        cf.read(ConfPath)
        if cf.has_section(section):
            if cf.has_option(section,option):
                tmpPath = cf.get(section,option)
                if tmpPath:
                    if not os.path.exists(tmpPath.strip()):
                        return tmpPath
        else:
            raise Exception("NO find Section %s in the conf %s" %(section,ConfPath))
        
        return ""
            
if __name__ == '__main__':
    
    #stockList = commRunTest().GetOverStock("D:\UML")
    #print str(stockList[0])
    #print str(stockList[1])
    #print str(stockList[2])
    
    #commRunTest().GetNewestFile("/home/wshi/home/IDC/log")
    #commRunTest().SmbCheck()
    #commRunTest().GetHDUse("/boot")
    #commRunTest().GetInodeUse("/dev/shm")
    #commRunTest().IsRunningOfPragram("./IDCBaseConv")
    #print "error list "
    
    strUnzipRunComm = "IDC_UnzipMass.py"
    strBaseRunComm = "IDCBaseConv"
    strMaseRunComm = "IDCMassConv"
    
    print "IDC_UnzipMass.py: %s" %str(commRunTest().IsRunningOfPragram(strUnzipRunComm))
    print "IDCBaseConv: %s" %str(commRunTest().IsRunningOfPragram(strBaseRunComm))
    print "IDCMassConv: %s" %str(commRunTest().IsRunningOfPragram(strMaseRunComm))
   
    #print commRunTest().ExistFileOrDirInConf("D:\IDC_UnzipMass.conf")
    
    
    
    
    
    
    
